// locutor
// (c) 2008-2009, Normen Müller, normen.mueller@gmail.com  
// $Id: Lexer.scala 2451 2009-10-01 14:04:14Z nmueller $
package locutor.svn

import scala.util.parsing.combinator.lexical._
import scala.util.parsing.input.CharArrayReader.EofCh
import scala.util.parsing.combinator.ImplicitConversions

/**
 * @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
 * @version 0.0.1 */
private [svn] class Lexer extends StdLexical with ImplicitConversions {
  override def token: Parser[Token] =
    ( revision ^^ NumericLit
    | string   ^^ StringLit
    | EofCh   ^^^ EOF
    | failure("Illegal character")
    )
  
  override def whitespace = rep(whitespaceChar | '#' ~ rep(chrExcept(EofCh)))
  
  def revision = ('-' ~ 'r' ~ opt(whitespace)) ~> digit ~ rep(digit) ^^ {
    case first ~ rest => first :: rest mkString ""
  }
  
  def string = rep(charSeq | chrExcept(' ', '\n', '\t', EofCh)) ^^ { _ mkString "" }
  
  def charSeq: Parser[String] =
    ( '\\' ~ '\"' ^^^ "\"" | '\\' ~ '\\' ^^^ "\\" | '\\' ~ '/'  ^^^ "/"
    | '\\' ~ 'b'  ^^^ "\b" | '\\' ~ 'f'  ^^^ "\f" | '\\' ~ 'n'  ^^^ "\n"
    | '\\' ~ 'r'  ^^^ "\r" | '\\' ~ 't'  ^^^ "\t" | '\\' ~ 'u' ~> unicodeBlock
    )
  
  val hexDigits = Set[Char]() ++ "0123456789abcdefABCDEF".toArray
  
  def hexDigit = elem("hex digit", hexDigits.contains(_))
  
  private def unicodeBlock = hexDigit ~ hexDigit ~ hexDigit ~ hexDigit ^^ {
    case a ~ b ~ c ~ d => new String(scala.io.UTF8Codec.encode(Integer.parseInt(List(a, b, c, d) mkString "", 16)))
  }
}